﻿'use strict';
angular.module('ecList', [ 'angular.filter'])
.factory('ecList', ['$compile', '$http', '$templateCache', '$location', '$q', '$state', '$injector', function ($compile, $http, $templateCache, $location, $q, $state, $injector) {
    var global = {
        device : 'common',
        promises: [],
        eventReceivers: [],
        setDevice: function (dev) {
            global.device = dev;
        },
        loadTemplate: function (url) {
            var pro = $http.get(url).then(function (response) {
                $compile(response.data);
                return response;
            });
            
            global.promises.push(pro);
            return pro;
        },

        compileTemplate: function (definition, $scope, element, defaultTemplateUrl) {
            var deferred = $q.defer();
            var template;
            if (definition.template) { // 直接设定模板内容
                template = definition.template;
                //element.html(template).show();
                //$compile(element.contents())($scope);
                var e = $compile(template)($scope);
                element.replaceWith(e);
                deferred.resolve();
            } else { // 指定模板的url
                var templateUrl = definition.templateUrl || defaultTemplateUrl; 
                $q.all(global.promises).then(function () {
                    template = $templateCache.get(templateUrl);
                    if (template) {
                        //element.html(template).show();
                        //$compile(element.contents())($scope);
                        var e = $compile(template)($scope);
                        element.replaceWith(e);
                    } else {
                        throw 'can not find template : ' + templateUrl;
                    }
                    deferred.resolve();
                });
            }
            return deferred.promise;
        },

        registerEventReceiver: function (urls) {
            var deferred = $q.defer();
            global.eventReceivers = [];
            if (urls && urls.length > 0) {
                require(urls, function () {
                    angular.forEach(arguments, function (arg) {
                        var receiver = $injector.invoke(arg);
                        global.eventReceivers.push(receiver);
                    });
                    deferred.resolve();
                });
            } else {
                deferred.resolve();
            }
            return deferred.promise;
        },

        handleEvent: function (name, args) {
            var deferred = $q.defer();
            var eventPromises = [];
            for (var i = 0; i < global.eventReceivers.length; i++) {
                if (angular.isFunction(global.eventReceivers[i][name])) {
                    var result = global.eventReceivers[i][name](args);
                    if (result) {
                        eventPromises.push(result);
                    }
                }
            }
            $q.all(eventPromises).then(function () {
                deferred.resolve();
            });
            return deferred.promise;
        },
        getParameters: function (name) {
        },
        setMode: function ($scope, configMode) {
            if (!$scope.ecMode) {
                var mode = $state.params.mode;
                if (mode) {
                    $scope.ecMode = mode;
                } else {
                    $scope.ecMode = 'view';
                }
            }
            if (angular.isDefined(configMode) && configMode != '') {
                $scope.ecMode = configMode;
            }
        },
        getView: function (schema) {
            var viewName = $state.params.view;

            if (!viewName || viewName == 0) {
                viewName = schema.list.defaultView;
            }
            for (var i = 0; i < schema.views.length; i++) {
                if (schema.views[i].name == viewName) {
                    return schema.views[i];
                }
            }
            throw "can not find ec view :" + viewName;
        },
        getForm: function ($scope) {
            if (!angular.isDefined($scope.formName) || $scope.formName == 0) {
                $scope.formName = $state.params.form;
                if ((!angular.isDefined($scope.formName) || $scope.formName == 0) && $scope.ecSchema.forms && $scope.ecSchema.forms.length > 0) {
                    return $scope.ecSchema.forms[0];
                }
            }
            if (angular.isDefined($scope.formName) && $scope.formName != 0) {
                for (var i = 0; i < $scope.ecSchema.forms.length; i++) {
                    if ($scope.ecSchema.forms[i].name == $scope.formName) {
                        return $scope.ecSchema.forms[i];
                    }
                }
            }
            throw "can not find ec form :" + $scope.formName;
        },
        getField : function (schema, fieldName) {
            var fieldNames = fieldName.split('.');
            var fields = schema.fields;
            for (var i = 0; i < fieldNames.length; i++) {
                for (var j = 0; j < fields.length; j++) {
                    if (fields[j].name == fieldNames[i]) {
                        if (i == fieldNames.length - 1) {
                            return fields[j];
                        } else {
                            if (fields[j].fields) {
                                fields = fields[j].fields;
                                break;
                            } else {
                                throw "can not find ec field :" + fieldName;
                            }
                                
                        }
                    }
                }
            }
            throw "can not find ec field :" + fieldName;
        },
        getLayout : function (layout) {
            var newLayout = angular.copy(layout);
            var layoutType = 'md';
            if (layout.type) {
                layoutType = layout.type;
            }
            if (layoutType == 'md') {
                newLayout.class = 'col-md-' + layout.width;
                newLayout.style = '';
                newLayout.labelClass = 'col-md-' + layout.labelWidth;
                newLayout.labelStyle = '';
                newLayout.controlClass = 'col-md-' + layout.controlWidth;
                newLayout.controlStyle = '';
            } else if (layoutType == 'px') {
                newLayout.class = '';
                newLayout.style = 'width:' + layout.width + 'px;';
                newLayout.labelClass = '';
                newLayout.labelStyle = 'width:' + layout.labelWidth + 'px;';
                newLayout.controlClass = '';
                newLayout.controlStyle = 'width:' + layout.controlWidth + 'px;';

            } else if (layoutType == 'class') {
                newLayout.class = layout.width;
                newLayout.style = '';
                newLayout.labelClass = layout.labelWidth;
                newLayout.labelStyle = '';
                newLayout.controlClass = layout.controlWidth;
                newLayout.controlStyle = '';

            } else if (layoutType == 'style') {
                newLayout.class = ''
                newLayout.style = layout.width;
                newLayout.labelClass = '';
                newLayout.labelStyle = layout.labelWidth;
                newLayout.controlClass = '';
                newLayout.controlStyle = layout.controlWidth;
            }
            return newLayout;
        },
        params: {}

    };
    return global;
}])
.directive('ecView', ['$rootScope', 'ecList', '$templateCache', '$location', function ($rootScope, ecList, $templateCache, $location) {
    return {
        restrict: 'E',
        scope: {
            items: '=ngModel',
            ecSchema: '=ecSchema',
            ecMode : '=?ecMode'
        },

        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });
            var render = function () {
                ecList.setMode($scope);
                
                var getCol = function (layoutField) {
                    var col = {};
                    col.layout = layoutField.layout;
                    col.title = layoutField.field.title;
                    col.field = layoutField.field;
                    return col;
                }

                var view = ecList.getView($scope.ecSchema);

                $scope.layoutFields = [];

                angular.forEach(form.layouts, function (layout) {
                    var field = ecList.getField($scope.ecSchema, layout.field);
                    $scope.layoutFields.push({ field: field, layout: layout });
                });


                $scope.view = view;
                $scope.cols = [];
                angular.forEach($scope.layoutFields, function (layoutField) {

                    $scope.cols.push(getCol(layoutField));


                });

                $scope.tableParams = new NgTableParams({
                }, {
                    dataset: $scope.items
                });

                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }
                
                ecList.compileTemplate($scope.view, $scope, element, "ec-list/view.html");
            };
            
        }
        
    };
}])
.directive('ecForm', ['$rootScope', 'ecList', '$templateCache', '$location', function ($rootScope, ecList, $templateCache, $location) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=ecSchema',
            ecMode: '=?ecMode',
            formName: '=?ecFormName'
        },

        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            var render = function () {
                ecList.setMode($scope);
                var form = ecList.getForm($scope);
                $scope.form = form;
                $scope.layoutFields = [];


                angular.forEach(form.layouts, function (layout) {
                    var field = ecList.getField($scope.ecSchema, layout.field);
                    $scope.layoutFields.push({ field: field, layout: ecList.getLayout(layout) });
                });



                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }
                ecList.handleEvent("beforeFormRender", $scope);
                ecList.compileTemplate($scope.form, $scope, element, "ec-list/form.html").then(function () {
                    ecList.handleEvent("afterFormRender", $scope);
                });
            };

        }
        
    };
}])
.directive('ecField', ['$rootScope', '$compile', 'ecList', '$templateCache', '$location', '$parse', function ($rootScope, $compile, ecList, $templateCache, $location, $parse) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=ecSchema',
            ecFieldName: '=?ecFieldName',
            field: '=?ecField',
            ecMode: '=?ecMode'
        },

        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            $scope.$watch('field', function () {
                if ($scope.field) {
                    render();
                }
            });

            var render = function () {
                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }
                
                

                if (!$scope.field) {
                    $scope.field = ecList.getField($scope.ecSchema, $scope.ecFieldName);
                }

                if (angular.isDefined($scope.field.mode) && $scope.field.mode != '') {
                    var configMode = $parse($scope.field.mode)($scope);
                    ecList.setMode($scope, configMode);
                } else {
                    ecList.setMode($scope);
                }

                var getTemplate = function (field) {

                    var firstUpcase = field.type[0].toUpperCase() + field.type.substring(1, field.type.length);
                    var directiveName = 'ecField' + firstUpcase;
                    var hasDirective = false;
                    angular.forEach(angular.module('ecList')._invokeQueue, function (invoke) {
                        if (invoke[1] == 'directive' && invoke[2][0] == directiveName) {
                            hasDirective = true;
                        }
                    });
                    var fieldType = ecList.device
                    if (hasDirective) {
                        fieldType = field.type;
                    }
                    return '<ec-field-' + fieldType + ' ng-model="item" name="' + $scope.name + '" ec-field="field" ec-mode="ecMode" ec-schema="ecSchema" ec-field-name="field.name"></ec-field-' + fieldType + '>';
                };

                //element.replaceWith(getTemplate($scope.field)).show();

                //$compile(element.contents())($scope);

                var e = $compile(getTemplate($scope.field))($scope);
                element.replaceWith(e);
            };


        }
    };
}])
.directive('ecFieldCommon', ['$rootScope', 'ecList', '$templateCache', '$location', 'defaultErrorMessageResolver', '$parse', function ($rootScope, ecList, $templateCache, $location, defaultErrorMessageResolver, $parse) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=?ecSchema',
            ecFieldName: '=?ecFieldName',
            field: '=?ecField',
            ecMode: '=?ecMode'
        },
        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            $scope.$watch('field', function () {
                if ($scope.field) {
                    render();
                }
            });

            var render = function () {

                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }

                ecList.setMode($scope);

                if (!$scope.field) {
                    $scope.field = ecList.getField($scope.ecSchema, $scope.ecFieldName);
                }

                if (angular.isDefined($scope.field.defaultValue) && !angular.isDefined($scope.item[$scope.field.name])) {
                    $scope.item[$scope.field.name] = $parse($scope.field.defaultValue)($scope);
                }

                $scope.validateExpression = "{";
                var validateMessages = [];
                if (angular.isDefined($scope.field.validates) && angular.isArray($scope.field.validates)) {
                    for (var i = 0; i < $scope.field.validates.length; i++) {
                        var key = $scope.name + '_' + i;
                        validateMessages.push({ key: key, message: $scope.field.validates[i].message });
                        $scope.validateExpression += key + ':(' + $scope.field.validates[i].expression + ')';
                        if (i != $scope.field.validates.length - 1) {
                            $scope.validateExpression += ',';
                        }
                    }
                }
                $scope.validateExpression += '}';

                defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) {
                    angular.forEach(validateMessages, function (vm) {
                        errorMessages[vm.key] = vm.message;
                    });
                });

                ecList.handleEvent("beforeFieldRender", $scope);

                if ($scope.field.type == 'select' && $scope.item[$scope.field.name] && $scope.field.options && $scope.field.options.length > 0) {
                    $scope.convertToNumber = typeof $scope.item[$scope.field.name] != $scope.field.options[0].value;
                }

                ecList.compileTemplate($scope.field, $scope, element, "ec-list/fields/" + $scope.field.type + '.html').then(function () {
                    ecList.handleEvent("afterFieldRender", $scope);
                });
                
            };

            
        }
        
    };
}])
.directive('ecFieldMobile', ['$rootScope', 'ecList', '$templateCache', '$location', '$parse', function ($rootScope, ecList, $templateCache, $location, $parse) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=?ecSchema',
            ecFieldName: '=?ecFieldName',
            field: '=?ecField',
            ecMode: '=?ecMode'
        },
        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            $scope.$watch('field', function () {
                if ($scope.field) {
                    render();
                }
            });

            var render = function () {

                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }

                ecList.setMode($scope);

                if (!$scope.field) {
                    $scope.field = ecList.getField($scope.ecSchema, $scope.ecFieldName);
                }

                if (angular.isDefined($scope.field.defaultValue) && !angular.isDefined($scope.item[$scope.field.name])) {
                    $scope.item[$scope.field.name] = $parse($scope.field.defaultValue)($scope);
                }

                $scope.validateExpression = "{";
                var validateMessages = [];
                if (angular.isDefined($scope.field.validates) && angular.isArray($scope.field.validates)) {
                    for (var i = 0; i < $scope.field.validates.length; i++) {
                        var key = $scope.name + '_' + i;
                        validateMessages.push({ key: key, message: $scope.field.validates[i].message });
                        $scope.validateExpression += key + ':(' + $scope.field.validates[i].expression + ')';
                        if (i != $scope.field.validates.length - 1) {
                            $scope.validateExpression += ',';
                        }
                    }
                }
                $scope.validateExpression += '}';

                //defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) {
                //    angular.forEach(validateMessages, function (vm) {
                //        errorMessages[vm.key] = vm.message;
                //    });
                //});

                ecList.handleEvent("beforeFieldRender", $scope);
                ecList.compileTemplate($scope.field, $scope, element, "ec-list/fields/" + $scope.field.type + '.html').then(function () {
                    ecList.handleEvent("afterFieldRender", $scope);
                });

            };


        }

    };
}])
.directive('ecFieldRepeat', ['$rootScope', 'ecList', '$templateCache', '$location', function ($rootScope, ecList, $templateCache, $location) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=?ecSchema',
            ecFieldName: '=?ecFieldName',
            field: '=?ecField',
            ecMode: '=?ecMode'
        },
        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            $scope.$watch('field', function () {
                if ($scope.field) {
                    render();
                }
            });

            var render = function () {
                ecList.setMode($scope);


                if (!$scope.field) {
                    $scope.field = ecList.getField($scope.ecSchema, $scope.ecFieldName);
                }

                $scope.layoutFields = [];

                angular.forEach($scope.field.layouts, function (layout) {
                    for (var i = 0 ; i < $scope.field.fields.length; i++) {
                        var subField = $scope.field.fields[i];
                        if (subField.name == layout.field) {
                            $scope.layoutFields.push({ field: subField, layout: ecList.getLayout(layout) });
                        }
                    }
                });

                $scope.add = function () {
                    if (!$scope.item[$scope.field.name]) {
                        $scope.item[$scope.field.name] = [];
                    }
                    var item = {};
                    ecList.handleEvent("beforeRepeatFieldAdd", $scope, item);
                    $scope.item[$scope.field.name].push(item);
                    
                };


                $scope.remove = function (subItem) {
                    ecList.handleEvent("beforeRepeatFieldRemove", $scope, subItem);
                    var index = $scope.item[$scope.field.name].indexOf(subItem);
                    $scope.item[$scope.field.name].splice(index, 1);
                };

                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }
                ecList.handleEvent("beforeFieldRender", $scope);
                ecList.compileTemplate($scope.field, $scope, element, "ec-list/fields/" + $scope.field.type + '.html').then(function () {
                    ecList.handleEvent("afterFieldRender", $scope);
                });
            };
            
        }

    };
}])
.directive('ecFieldTemplate', ['$rootScope', 'ecList', '$templateCache', '$location', function ($rootScope, ecList, $templateCache, $location) {
    return {
        restrict: 'E',
        scope: {
            item: '=ngModel',
            ecSchema: '=?ecSchema',
            ecFieldName: '=?ecFieldName',
            field: '=?ecField',
            ecMode: '=?ecMode'
        },
        link: function ($scope, element, attrs, ctrl) {
            $scope.list = ecList;
            $scope.$watch('ecSchema', function () {
                if ($scope.ecSchema) {
                    render();
                }
            });

            $scope.$watch('field', function () {
                if ($scope.field) {
                    render();
                }
            });

            

            var render = function () {
                ecList.setMode($scope);


                if (!$scope.field) {
                    $scope.field = ecList.getField($scope.ecSchema, $scope.ecFieldName);
                }

                
                $scope.name = attrs.name;
                if (!angular.isDefined($scope.name)) {
                    $scope.name = 'ec';
                }

                $scope.templateData = {
                    field: $scope.field,
                    name: $scope.name,
                    mode: $scope.ecMode,
                    item : $scope.item
                };

                ecList.handleEvent("beforeFieldRender", $scope);
                ecList.compileTemplate($scope.field, $scope, element, "ec-list/fields/" + $scope.field.type + '.html').then(function () {
                    ecList.handleEvent("afterFieldRender", $scope);
                });

                $scope.$watch('item', function () {
                    if ($scope.$csTemplates) {
                        $scope.$csTemplates[$scope.field.templateFieldUrl.replace(/\//g, '_')].reload();
                    }

                });
            };

        }

    };
}])
.run(['$http', '$templateCache', function ($http, $templateCache) {

}]);